package com.owc.service.impl.admin;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.owc.common.exception.BadRequestException;
import com.owc.common.redis.CacheBuildKey;
import com.owc.common.redis.RedisUtil;
import com.owc.common.Const.Const;
import com.owc.common.tool.DateUtils;
import com.owc.dao.RefreshRecordMapper;
import com.owc.dao.TokenBalanceMapper;
import com.owc.domain.BaseResult;
import com.owc.domain.dto.admin.FundsDTO;
import com.owc.domain.dto.admin.RefreshInfoDTO;
import com.owc.domain.entity.RefreshRecord;
import com.owc.domain.vo.admin.FundsVo;
import com.owc.filter.content.SecurityContextHolder;
import com.owc.filter.content.UserDetail;
import com.owc.service.WalletServer;
import com.owc.service.admin.FundsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @Author xiaom
 * @Date 2019/12/20 10:19
 * @Version 1.0.0
 * @Description <>
 **/
@Service
@Slf4j
public class FundsServiceImpl implements FundsService {

    @Resource
    private TokenBalanceMapper tokenBalanceMapper;
    @Resource
    private RefreshRecordMapper refreshRecordMapper;
    @Autowired
    private WalletServer walletServer;


    @Override
    public BaseResult<List<FundsDTO>> list(FundsVo fundsVo) {
        PageHelper.startPage(fundsVo.getPageIndex(),fundsVo.getPageSize());
        List<FundsDTO> tokenBalances = tokenBalanceMapper.selectByQueryModel(fundsVo);
        PageInfo<FundsDTO> pageInfo = new PageInfo<>(tokenBalances);
        return BaseResult.success(tokenBalances,pageInfo.getTotal());
    }

    @Override
    public Boolean refreshBalance(FundsVo fundsVo) {
        Assert.notNull(fundsVo.getTokenName(),"请选择代币名称");

        //获取所有当前代币的钱包地址
        List<String> addressList = tokenBalanceMapper.selectAddressListByTokenName(fundsVo.getTokenName());
        if(addressList == null || addressList.isEmpty()){
            throw new BadRequestException("没有可刷新的钱包地址");
        }
        //缓存状态
        signTokenRefreshStatus(fundsVo.getTokenName());
        //调用钱包服务器接口,获取对应的余额
        refreshTokenBalance(addressList,fundsVo.getTokenName());
        return true;
    }

    @Override
    public RefreshInfoDTO getRefreshInfo(String tokenName) {

        RefreshInfoDTO refreshInfoDTO = new RefreshInfoDTO(0);

        RefreshRecord refreshRecord = refreshRecordMapper.selectByTokenName(tokenName);
        if(refreshRecord == null){
            return refreshInfoDTO;
        }

        refreshInfoDTO.setStatus(isRefreshStatus(tokenName) ? 0 : 1);
        refreshInfoDTO.setLastUpdateTime(refreshRecord.getStartTime());

        return refreshInfoDTO;
    }

    private void refreshTokenBalance(List<String> addressList, String tokenName) {
        UserDetail userDetail = SecurityContextHolder.getCurrentUser();
        new Thread(() -> {
            log.info("开始刷新[{}] 代币的用户钱包余额",tokenName);
            long start = System.currentTimeMillis();
            Long recordId = createRefreshRecord(tokenName,userDetail.getUser().getId(),userDetail.getUser().getUsername());
            for (String address : addressList) {
                try {
                    updateUserWalletBalance(address,tokenName);
                } catch (Exception e) {
                    log.error("更新钱包余额异常 address:[{}] message:[{}]",address,e.getMessage());
                }
            }
            log.info("刷新[{}]代币钱包余额完成 耗时:{}",tokenName,(System.currentTimeMillis() - start));
            updateRefreshRecordEndTime(recordId);
            refreshTokenFinish(tokenName);
        }).start();
    }

    @Override
    public void updateUserWalletBalance(String address,String tokenName) {
        try {
            BigDecimal balance = walletServer.getPlatformBalance(Const.ETH,tokenName,address);
            tokenBalanceMapper.updateWalletBalance(balance,tokenName,address);
            log.info("刷新钱包余额, address:[{}], tokenName:[{}] balance:[{}]",address,tokenName,balance);
        } catch (Exception e) {
            log.error("更新钱包余额异常 address:[{}] message:[{}]",address,e.getMessage());
            e.printStackTrace();
        }
    }

    private Long createRefreshRecord(String tokenName,Long userId,String userName) {

        RefreshRecord refreshRecord = new RefreshRecord();
        refreshRecord.setOperUserId(userId);
        refreshRecord.setOperUserName(userName);
        refreshRecord.setTokenName(tokenName);
        refreshRecord.setStartTime(DateUtils.formatYMDHMS(new Date()));
        refreshRecordMapper.insert(refreshRecord);
        return refreshRecord.getId();
    }

    private void updateRefreshRecordEndTime(Long recordId){
        RefreshRecord refreshRecord = new RefreshRecord();
        refreshRecord.setId(recordId);
        refreshRecord.setEndTime(DateUtils.formatYMDHMS(new Date()));
        refreshRecordMapper.updateByPrimaryKeySelective(refreshRecord);
    }

    private void signTokenRefreshStatus(String tokenName){
        RedisUtil.getInstance().set(CacheBuildKey.buildTokenRefreshKey(tokenName),1, (long) CacheBuildKey._TIME_HOUR_ONE);
    }

    private void refreshTokenFinish(String tokenName){
        RedisUtil.getInstance().del(CacheBuildKey.buildTokenRefreshKey(tokenName));
    }

    private boolean isRefreshStatus(String tokenName){
        return RedisUtil.getInstance().get(CacheBuildKey.buildTokenRefreshKey(tokenName)) == null;
    }
}
